/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.csp.sentinel.demo.cluster.init;

import java.util.List;
import java.util.Set;

import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterParamFlowRuleManager;
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.demo.cluster.DemoConstants;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.property.SentinelProperty;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.util.function.Function;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

/**
 * 若不希望手动注册数据源，可以借助 Sentinel 的 InitFunc SPI 扩展接口。只需要实现自己的 InitFunc 接口，在 init 方法中编写注册数据源的逻辑。比如：
 *
 * @author Eric Zhao
 */
public class DemoClusterServerInitFunc implements InitFunc {

    private final String remoteAddress = "localhost:8848";
    private final String groupId = "SENTINEL_GROUP";
    private final String namespaceSetDataId = "cluster-server-namespace-set";
    private final String serverTransportDataId = "cluster-server-transport-config";

    @Override
    public void init() throws Exception {
        // Register cluster flow rule property supplier which creates data source by namespace.
        ClusterFlowRuleManager.setPropertySupplier(new Function<String, SentinelProperty<List<FlowRule>>>() {
            @Override
            public SentinelProperty<List<FlowRule>> apply(String namespace) {
                ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
                        namespace + DemoConstants.FLOW_POSTFIX,
                        new Converter<String, List<FlowRule>>() {
                            @Override
                            public List<FlowRule> convert(String source) {
                                return JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
                                });
                            }
                        });
                return ds.getProperty();
            }
        });
        // Register cluster parameter flow rule property supplier.
        ClusterParamFlowRuleManager.setPropertySupplier(new Function<String, SentinelProperty<List<ParamFlowRule>>>() {
            @Override
            public SentinelProperty<List<ParamFlowRule>> apply(String namespace) {
                ReadableDataSource<String, List<ParamFlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
                        namespace + DemoConstants.PARAM_FLOW_POSTFIX,
                        source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {
                        }));
                return ds.getProperty();
            }
        });

        // Server namespace set (scope) data source.
        ReadableDataSource<String, Set<String>> namespaceDs = new NacosDataSource<>(remoteAddress, groupId,
                namespaceSetDataId, new Converter<String, Set<String>>() {
            @Override
            public Set<String> convert(String source) {
                return JSON.parseObject(source, new TypeReference<Set<String>>() {
                });
            }
        });
        ClusterServerConfigManager.registerNamespaceSetProperty(namespaceDs.getProperty());
        // Server transport configuration data source.
        ReadableDataSource<String, ServerTransportConfig> transportConfigDs = new NacosDataSource<>(remoteAddress,
                groupId, serverTransportDataId,
                new Converter<String, ServerTransportConfig>() {
                    @Override
                    public ServerTransportConfig convert(String source) {
                        return JSON.parseObject(source, new TypeReference<ServerTransportConfig>() {
                        });
                    }
                });
        ClusterServerConfigManager.registerServerTransportProperty(transportConfigDs.getProperty());
    }
}
